#pragma once

#ifdef USE_CAIRO
#include "cairo/cairo.h"
#include "cairo/cairo-ft.h"
#include "Common.h"
#include "Paint.h"

namespace LuaGui {
	class CairoImage {
	public:
		CairoImage(const std::string& filepath);
		~CairoImage();

		cairo_surface_t* GetCairoSurface();
		void Refresh();
		bool IsExpired();
		static CairoImage* GetImageByFilePath(const std::string& filepath);
		static void CollectGarbage();

	private:
		cairo_surface_t* m_surface;
		std::string m_filepath;
		unsigned long long m_expired_timestamp;

	private:
		static const unsigned long MAX_ALIVE_TIME = 1000;        // ms
		static const unsigned long MAX_CACHE_IMAGE_COUNT = 40;
		static std::unordered_map<std::string, CairoImage*> s_images;
	};

	class CairoPaint : public Paint {
	public:
		CairoPaint(cairo_t* cr = nullptr);
		~CairoPaint();

		void SetCairo(cairo_t* cr);
		cairo_t* GetCairo() { return m_cr; }

	public:
		virtual void DrawPoint(double x, double y);
		virtual void MoveTo(double x, double y);
		virtual void LineTo(double x, double y);
		virtual void DrawLine(double x1, double y1, double x2, double y2, bool stroke);
		virtual void DrawTriangle(double x1, double y1, double x2, double y2, double x3, double y3, bool fill = true, bool stroke = false);
		virtual void DrawCurve(double x1, double y1, double x2, double y2, double x3, double y3, bool fill = true, bool stroke = false);
		virtual void DrawRectangle(double x, double y, double w, double h, bool fill = true, bool stroke = false);
		virtual void DrawArc(double cx, double cy, double radius, double angle1, double angle2, bool fill = true, bool stroke = false);
		virtual void DrawPolygon(std::vector<double>& points, bool fill = true, bool stroke = false);
		virtual void DrawText(double x, double y, const char* utf8);
		virtual double GetTextWidth(const char* utf8, double font_size);
		virtual double GetTextWidth(const wchar_t* unicode, double font_size);
		virtual void DrawNineImage(double x, double y, double w, double h, const std::string& utf8_png_filename, double l = 0, double t = 0, double r = 0, double b = 0);
		virtual void DrawNineImage(double x, double y, double w, double h, const std::wstring& unicode_png_filename, double l = 0, double t = 0, double r = 0, double b = 0);
		virtual void DrawImage(double dx, double dy, double dw, double dh, const std::string& utf8_png_filename, double sx = 0, double sy = 0, double sw = -1, double sh = -1, bool is_scale = false);
		virtual void DrawImage(double dx, double dy, double dw, double dh, const std::wstring& unicode_png_filename, double sx = 0, double sy = 0, double sw = -1, double sh = -1, bool is_scale = false);
		virtual void Stroke();
		virtual void Fill();

		// pixmal data
		virtual void Clear();
		virtual void Flush();
		virtual unsigned char* GetData();
		virtual void Dump();
		virtual void WriteToPng(const char* utf8_filename);

		// Transformation
		virtual void Translate(double tx, double ty);
		virtual void Scale(double sx, double sy);
		virtual void Rotate(double angle);
		//virtual void Transform() = 0;

		virtual void Clip();
		virtual void Save();
		virtual void Restore();

		virtual bool SetFont(std::string font_file);
		virtual bool SetFont(unsigned char* data, uint32_t size);
	public:
		void DrawText(double x, double y, double w, double h, const wchar_t* unicode, const int x_align, const int y_align, bool is_clip);
		void DrawString(double x, double y, const char* utf8) { DrawText(x, y, utf8); }
		void DrawString(double x, double y, const wchar_t* unicode) { DrawText(x, y, LuaGui::UnicodeToUtf8(unicode).c_str()); }
		void DrawString(double x, double y, double w, double h, const char* utf8, const int x_align, const int y_align, bool is_clip) { Paint::DrawText(x, y, w, h, utf8, x_align, y_align, is_clip); }
		void DrawString(double x, double y, double w, double h, const wchar_t* unicode, const int x_align, const int y_align, bool is_clip) { DrawText(x, y, w, h, unicode, x_align, y_align, is_clip); }


	private:
		void DrawImage(double dx, double dy, double dw, double dh, cairo_surface_t* image_surface, double sx = 0, double sy = 0, double sw = -1, double sh = -1, bool is_scale = false);

	private:
		FT_Library m_ft_library;
		FT_Face m_ft_face;
		cairo_t* m_cr;
		cairo_font_face_t* m_font_face;
	};
}
#endif // USE_CAIRO

